package server;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Hashtable;

import GUI.ResultDisplay;

import ocsf.server.ConnectionToClient;

import logic.Book;
import logic.Loan;
import logic.Member;
import logic.Message;
import logic.Order;
import logic.SystemMesseges;

public class LoanController {

	private DB_Manager DB;
	private OBL_Server parent;
	
	public LoanController(OBL_Server parent,DB_Manager DB) {
		this.parent = parent;
		this.DB = DB;
	}
	
	
	/**
	 * This function will search the DB for Loan by the requested fields
	 * The Result will be sent as a Message to the client
	 * @param received - the Message object containing the fields and their requested values
	 * @param client - the client which requested the search
	 */
	public void SearchLoan(Message received, ConnectionToClient client){
		
		ArrayList<String> incommingIndex = received.GetMessageIndexes();
		ArrayList<Object> incommingData = received.GetMessageData();
				
		ResultSet rs = QueryLoan(incommingIndex, incommingData);
		
		ArrayList<Loan> loanList = SeralizeResultSet(rs);
		
		ArrayList<String> index = new ArrayList<String>();
		index.add("INDICATOR");
		index.add("RESULTSET");
		index.add("DIRECTOR");
		ArrayList<Object> data = new ArrayList<Object>();
		data.add(ResultDisplay.LOAN);
		data.add(loanList);
		data.add(received.GetMessageData().get(0));

		int action = Message.SEARCH_LOAN_RESPONSE;
		
		Message toSend = new Message(index, data, action);
		
		try{
			client.sendToClient(toSend);
		}catch(IOException e){
			parent.Log("[SearchLoan] IOException - sending result. [" + client.getInetAddress().toString() + "] " + e.getMessage());
		}
		
		
	}
	
	
	
	/**
	 * This function querys the DB for all loans that were closed between startdate and enddate
	 * @param startDate - the first day of the query
	 * @param endDate - the last day of the query
	 * @return ArrayList<Loan> - ArrayList that contains all the qualifying loans
	 */
	public ArrayList<Loan> GetLoansForDates(String startDate,String endDate){
		
		BookController bookController = new BookController(parent, DB);
		MemberController memberController = new MemberController(parent, DB);

		ArrayList<Loan> loanList = new ArrayList<Loan>();
			
		try{
			
			String query = "SELECT * FROM loans WHERE ACTUAL_RETURN_DATE BETWEEN '" + startDate +"' AND '" + endDate + "'";
			ResultSet rs = DB.Query(query);
			while(rs.next()){
				String bName = bookController.getNameForBook(String.valueOf(rs.getInt("BID")));
				String mName = memberController.getMemberName(String.valueOf(rs.getInt("UID")));
				
				//Loan(int LID, int UID,int BID,int BCID,String LoanDate,String ActualReturnDate,String ReturnDate,
				//int extended, int status,int HotBook,int BookStatus,String memberName,String bookName)
		Loan loan = new Loan(rs.getInt("LID"),rs.getInt("UID"),rs.getInt("BID"),rs.getInt("BCID"),rs.getString("LOAN_DATE"),
				rs.getString("RETURN_DATE"),rs.getString("ACTUAL_RETURN_DATE"),rs.getInt("EXTEND"),
				rs.getInt("STATUS"),rs.getInt("HOT_BOOK"),rs.getInt("BOOKSTATUS"),mName,bName);
		
				loanList.add(loan);
			}
			return loanList;
		}catch(SQLException e){
			parent.Log("[GetLoansForDates] IOException. " + e.getMessage());
		}catch(ClassCastException cl){
			parent.Log("[GetLoansForDates] ClassCastException. " + cl.getMessage());
		}catch(NullPointerException nul){
			parent.Log("[GetLoansForDates] NullPointerException. " + nul.getMessage());
		}

		return null;
	}
	
	
	/**
	 * This function querys the DB for all loans that were closed between startdate and enddate, and in DELAY
	 * @param startDate - the first day of the query
	 * @param endDate - the last day of the query
	 * @return ArrayList<Loan> - ArrayList that contains all the qualifying loans
	 */
	public ArrayList<Loan> GetLateLoansForDates(String startDate,String endDate,String bidQuery){
		
		BookController bookController = new BookController(parent, DB);
		MemberController memberController = new MemberController(parent, DB);

		ArrayList<Loan> loanList = new ArrayList<Loan>();
			
		String query = "SELECT * FROM loans WHERE ACTUAL_RETURN_DATE BETWEEN '" + startDate +"' AND '" + endDate + 
				"' AND ACTUAL_RETURN_DATE > RETURN_DATE" + bidQuery;

		try{
			
			ResultSet rs = DB.Query(query);
			
			while(rs.next()){
				String bName = bookController.getNameForBook(String.valueOf(rs.getInt("BID")));
				String mName = memberController.getMemberName(String.valueOf(rs.getInt("UID")));
				
				//Loan(int LID, int UID,int BID,int BCID,String LoanDate,String ActualReturnDate,String ReturnDate,
				//int extended, int status,int HotBook,int BookStatus,String memberName,String bookName)
		Loan loan = new Loan(rs.getInt("LID"),rs.getInt("UID"),rs.getInt("BID"),rs.getInt("BCID"),rs.getString("LOAN_DATE"),
				rs.getString("RETURN_DATE"),rs.getString("ACTUAL_RETURN_DATE"),rs.getInt("EXTEND"),
				rs.getInt("STATUS"),rs.getInt("HOT_BOOK"),rs.getInt("BOOKSTATUS"),mName,bName);
		
				loanList.add(loan);
			}
			return loanList;
		}catch(SQLException e){
			parent.Log("[GetLateLoansForDates] IOException. " + e.getMessage());
		}catch(ClassCastException cl){
			parent.Log("[GetLateLoansForDates] ClassCastException. " + cl.getMessage());
		}catch(NullPointerException nul){
			parent.Log("[GetLateLoansForDates] NullPointerException. " + nul.getMessage());
		}

		return null;
	}

	
	/**
	 * This Function convert a ResultSet into ArrayList<Loan> for sending as a Message
	 * (ResultSet is not seralizeable)
	 * @param rs - the ResultSet to conver
	 * @return - ArrayList<Loan> which conatins all the loans in the ResultSet
	 */
	public ArrayList<Loan> SeralizeResultSet(ResultSet rs){
		
		BookController bookController = new BookController(parent, DB);
		MemberController memberController = new MemberController(parent, DB);
		
		ArrayList<Loan> loanList = new ArrayList<Loan>();

		try{
			while(rs.next()){
				String bName = bookController.getNameForBook(String.valueOf(rs.getInt("BID")));
				String mName = memberController.getMemberName(String.valueOf(rs.getInt("UID")));
				
				//Loan(int LID, int UID,int BID,int BCID,String LoanDate,String ActualReturnDate,String ReturnDate,
						//int extended, int status,int HotBook,int BookStatus,String memberName,String bookName)
				Loan loan = new Loan(rs.getInt("LID"),rs.getInt("UID"),rs.getInt("BID"),rs.getInt("BCID"),rs.getString("LOAN_DATE"),
						rs.getString("RETURN_DATE"),rs.getString("ACTUAL_RETURN_DATE"),rs.getInt("EXTEND"),
						rs.getInt("STATUS"),rs.getInt("HOT_BOOK"),rs.getInt("BOOKSTATUS"),mName,bName);
				
				loanList.add(loan);
			}
			
			return loanList;
		}catch(SQLException e){
			parent.Log("[SeralizeResultSet] IOException. " + e.getMessage());
		}catch(ClassCastException cl){
			parent.Log("[SeralizeResultSet] ClassCastException. " + cl.getMessage());
		}catch(NullPointerException nul){
			parent.Log("[SeralizeResultSet] NullPointerException. " + nul.getMessage());
		}
		return null;
	}
	
	
	/**
	 * This function looks for the minimum RETURN_DATE in the DB for the selected book
	 * @param BID - the BID to look for
	 * @return String as the date
	 */
	public String GetNextDateForBook(int BID){
		String query = "SELECT min(RETURN_DATE) as NEXTBOOK FROM loans WHERE BID = '" + BID + "' AND STATUS = '1';";

		try{
			ResultSet rs = DB.Query(query);
			String date = null;
			while(rs.next()){
				date = rs.getString("NEXTBOOK");
			}
			return date;
		}catch(SQLException e){
			parent.Log("[GetNextDateForBook] IOException. " + e.getMessage());
		}catch(ClassCastException cl){
			parent.Log("[GetNextDateForBook] ClassCastException. " + cl.getMessage());
		}catch(NullPointerException nul){
			parent.Log("[GetNextDateForBook] NullPointerException. " + nul.getMessage());
		}
		
		return null;
	}
	
	
	/**
	 * This function is private, meant to query the actual DB for the fields and return the ResultSet
	 * @param fields - the fields to query by
	 * @param data - the data to query by
	 * @return ResultSet which contains all qualified tuples
	 */
	private ResultSet QueryLoan(ArrayList<String> fields,ArrayList<Object> data){
		
		String query = "SELECT * FROM loans";
		if (fields.size() > 1) {

			query += " WHERE " + (String)fields.get(1) + " = '" + (String)data.get(1) + "'";
			
			for(int i=2; i < fields.size(); i++){
				query += " AND " + (String)fields.get(i) + " = '" + (String)data.get(i) + "'";
			}
			query += " AND (STATUS = '" + Loan.OPEN_LOAN_VALID + "' OR STATUS + '" + Loan.OPEN_LOAN_DELAYED + "');";
		}
		
		return DB.Query(query);
	}
	
	
	
	/**
	 * This function extends a loan. Manual - Librarian, Automatic - Student
	 * @param msg - the Message object containing the relevant information
	 * @param client - the client which requested the extension
	 */
	public void ExtendLoan(Message msg,ConnectionToClient client){
		
		ArrayList<Object> data = msg.GetMessageData();
		
		try{
			int days = 0;
			int LID = (Integer)data.get(0);
		
			String type = (String)data.get(1);
			if (type.equals("AUTOMATIC")){
				days = Loan.EXTEND_LOAN_TIME;
			}else if(type.equals("MANUAL")){
				days = Integer.parseInt((String)data.get(2));	
			}
			
			String search = "SELECT * FROM loans WHERE LID = '" + LID + "'";
			ResultSet rs = DB.Query(search);
			rs.next();
			String curReturnDate = rs.getString("RETURN_DATE");
			
			
			int year = Integer.parseInt(curReturnDate.substring(0, 4));
			int month = Integer.parseInt(curReturnDate.substring(5, 7));
			int day = Integer.parseInt(curReturnDate.substring(8, curReturnDate.length()));

			Calendar currentReturn = Calendar.getInstance();
			currentReturn.set(year, month-1, day);
			currentReturn.setLenient(false);
			currentReturn.getTime();
			currentReturn.add(Calendar.DAY_OF_MONTH, days);
			
			String newDate = currentReturn.get(Calendar.YEAR) + "-";
			if (currentReturn.get(Calendar.MONTH) < 10) newDate += "0" + (currentReturn.get(Calendar.MONTH) + 1) + "-";
			else newDate += (currentReturn.get(Calendar.MONTH) + 1) + "-";
			if (currentReturn.get(Calendar.DAY_OF_MONTH) < 10) newDate += "0" + currentReturn.get(Calendar.DAY_OF_MONTH);
			else newDate += currentReturn.get(Calendar.DAY_OF_MONTH);
			
			
			String updateQuery = "UPDATE loans SET RETURN_DATE = '" + newDate + "' , EXTEND = '1' WHERE LID = '" + LID + "'";
			if(DB.Update(updateQuery) == 0){
				SendOutputToUser("ERROR","Could not extend loan",Message.EXTEND_LOAN_RESPONSE,client);
				parent.Log("[ExtendLoan] Could not extend loan. [" + client.getInetAddress() + "].");
				return;
			}
			
			SendOutputToUser("OK","Loan Extended",Message.EXTEND_LOAN_RESPONSE,client);
			
			//TODO send to librarians
			
			
			//TODO setnd sysmsg
			
		}catch(ClassCastException cl){
			parent.Log("[ExtendLoan] ClassCastException. " + cl.getMessage());
			SendOutputToUser("ERROR","Could not extend loan",Message.EXTEND_LOAN_RESPONSE,client);
		}catch(IndexOutOfBoundsException in){
			parent.Log("[ExtendLoan] IndexOutOfBoundsException. " + in.getMessage());
			SendOutputToUser("ERROR","Could not extend loan",Message.EXTEND_LOAN_RESPONSE,client);
		}catch(SQLException sql){
			parent.Log("[ExtendLoan] SQLException. " + sql.getMessage());
			SendOutputToUser("ERROR","Could not extend loan",Message.EXTEND_LOAN_RESPONSE,client);
		}
	}
	
	
	
	/**
	 * This Function creates the Loan object in the DB
	 * @param loan - the Message object containing the loan's information
	 * @param client - Client which created the loan
	 * @return 1 for valid, 0 for error
	 */
	public synchronized int CreateLoan(Message loan,ConnectionToClient client){
		
		ArrayList<Object> data = loan.GetMessageData();
		
		String UID = (String)data.get(1);
		String BID = (String)data.get(0);
		
		String query =  "SELECT * FROM loans WHERE UID = '" + UID + 
				"' AND BID = '" + BID + "' AND (STATUS = '"+ Loan.OPEN_LOAN_DELAYED +"' OR STATUS = '" + Loan.OPEN_LOAN_VALID + "');";
		
		try{
			ResultSet rs = DB.Query(query);
			
			BookController bookController = new BookController(parent, DB);
			MemberController memberController = new MemberController(parent, DB);
			OrderController orderController = new OrderController(parent,DB);
			
			if (!memberController.ValidateMember(UID)){
				SendOutputToUser("ERROR","No such member",Message.CREATE_LOAN_RESPONSE,client);
				return 0;
				
			}else if (!bookController.ValidateBook(BID)){
				SendOutputToUser("ERROR","No such book",Message.CREATE_LOAN_RESPONSE,client);
				return 0;
			}
			
			if (!memberController.getMemberCardStatus(UID)) {
				SendOutputToUser("ERROR","Student membercard status is not valid",Message.CREATE_LOAN_RESPONSE,client);
				return 0;
			}		
			
			int copies = bookController.getAvailableCopies(BID);
			
			if (copies > 0){
				int orders = orderController.getOpenOrdersForBook(BID);
				if (orders == copies){
					SendOutputToUser("ERROR","All available copies has been ordered.",Message.CREATE_LOAN_RESPONSE,client);
					return 0;
				}
			}else{
				SendOutputToUser("ERROR","No available copies",Message.CREATE_LOAN_RESPONSE,client);
				return 0;
			}
				
		
			while(rs.next()){
				SendOutputToUser("ERROR","Loan already exist",Message.CREATE_LOAN_RESPONSE,client);
				return 0;
			}
			
			if (orderController.CloseTheOrder(BID, UID,Order.ORDER_FINISHED) == -1){
				SendOutputToUser("ERROR","Could not remove the order for the loan",Message.CREATE_LOAN_RESPONSE,client);
				parent.Log("[CreateLoan] Could not remove the order for the loan. [" + client.getInetAddress() + "].");
				return 0;
			}
			
			int availableCopies = bookController.getAvailableCopies(BID);
			bookController.setAvailableCopies(BID, availableCopies-1);
			
			//Loan does not exist, ok to add!
			Calendar today = Calendar.getInstance();
			String currDate = today.get(Calendar.YEAR) + "-";
			if (today.get(Calendar.MONTH) < 10) currDate += "0" + (today.get(Calendar.MONTH) + 1) + "-";
			else currDate += (today.get(Calendar.MONTH) + 1) + "-";
			if (today.get(Calendar.DAY_OF_MONTH) < 10) currDate += "0" + today.get(Calendar.DAY_OF_MONTH);
			else currDate += today.get(Calendar.DAY_OF_MONTH);
			
			int hot;
			String returnDate;
			if (bookController.isHotBook(BID)){
				hot = 1;
				today.add(Calendar.DAY_OF_MONTH, 3);
				
			}else {
				hot = 0;
				today.add(Calendar.DAY_OF_MONTH, 14);
			}
			
			returnDate = today.get(Calendar.YEAR) + "-";
			if (today.get(Calendar.MONTH) < 10) returnDate += "0" + (today.get(Calendar.MONTH) + 1) + "-";
			else returnDate += (today.get(Calendar.MONTH) + 1) + "-";
			if (today.get(Calendar.DAY_OF_MONTH) < 10) returnDate += "0" + today.get(Calendar.DAY_OF_MONTH);
			else returnDate += today.get(Calendar.DAY_OF_MONTH);
			
			int BCID = bookController.AllocateBCID(BID);
			if (BCID == -1){
				parent.Log("[CreateLoan] Could not find available book copy(bug),BID: " + BID + ", BCID: " + BCID +  "[" + client.getInetAddress() + "].");
				SendOutputToUser("ERROR","Could not find available book copy(bug)",Message.CREATE_ORDER_RESPONSE,client);
				return 0;
			}
			
			
			String insertQuery = "INSERT INTO LOANS " +
					"(LID,UID,BID,BCID,LOAN_DATE,RETURN_DATE,ACTUAL_RETURN_DATE,EXTEND,STATUS,HOT_BOOK,BOOKSTATUS) VALUES" +
					"(null,'" + UID + "','" + BID + "','" + BCID + "','" + currDate + 
					"','" + returnDate + "',null,'0','" + Loan.OPEN_LOAN_VALID + "','"
					+ hot + "','" + Loan.LOAN_BOOK_VALID + "');";
			if (DB.Update(insertQuery) == 0){
				parent.Log("[CreateLoan] Could not update DB for new loan. query: " + insertQuery + "[" + client.getInetAddress() + "].");
				SendOutputToUser("ERROR","Could not update DB for new loan",Message.CREATE_ORDER_RESPONSE,client);
				return 0;
				
			}
			
			if(bookController.SetBCIDStatus(BID, BCID, Book.BOOK_COPY_NOT_AVAILABLE) == 0){
				parent.Log("[CreateLoan] Could not set DB for book copy, BID: " + BID + ",BCID: " + BCID + ",STATUS: " + Book.BOOK_COPY_NOT_AVAILABLE + "[" + client.getInetAddress() + "].");
				SendOutputToUser("ERROR","Could not set DB for book copy",Message.CREATE_ORDER_RESPONSE,client);
				return 0;
			}
			
			SendOutputToUser("OK","Loan Created",Message.CREATE_ORDER_RESPONSE,client);
			
			String name = bookController.getNameForBook(BID);
			MessageController messageController = new MessageController(parent, DB);
			
			Calendar todayDate = Calendar.getInstance();
			String currDateM = todayDate.get(Calendar.YEAR) + "-";
			if (todayDate.get(Calendar.MONTH) < 10) currDateM += "0" + (todayDate.get(Calendar.MONTH) + 1) + "-";
			else currDateM += (todayDate.get(Calendar.MONTH) + 1) + "-";
			if (todayDate.get(Calendar.DAY_OF_MONTH) < 10) currDateM += "0" + todayDate.get(Calendar.DAY_OF_MONTH);
			else currDateM += todayDate.get(Calendar.DAY_OF_MONTH);
			
			ArrayList<Object> msgData = new ArrayList<Object>();
			msgData.add(String.valueOf(UID));
			msgData.add("Book loan update!");
			msgData.add("A book was loaned for you. (" + name + ")");
			msgData.add(String.valueOf(SystemMesseges.SYSTEM_MESSAGE));
			msgData.add(currDateM);
			msgData.add(String.valueOf(SystemMesseges.MESSAGE_UNREAD));
			messageController.CreateMessage(msgData, client);
			
			
			return 1;
			
		}catch(SQLException e){
			parent.Log("[CreateLoan] SQLException. [" + client.getInetAddress() + "]. " + e.getMessage());
			return 0;
		}catch(IndexOutOfBoundsException in){
			parent.Log("[CreateLoan] IndexOutOfBoundsException. [" + client.getInetAddress() + "]. " + in.getMessage());
			return 0;
		}
	}

	
	
	/**
	 * This function closes a loan, with the inserted values inside the message
	 * @param received - the Message Object containing the loan information
	 * @param client - the client which requested the return
	 */
	public int ReturnBook(Message received,ConnectionToClient client){
		ArrayList<Object> data = received.GetMessageData();
		
		try{
			
			String BID = (String)data.get(0);
			String BCID = (String)data.get(1);
			int BOOKSTATUS = (Integer)data.get(2);
			String UID = (String)data.get(3);
			
			BookController bookController = new BookController(parent, DB);
			MemberController memberController = new MemberController(parent, DB);
			OrderController orderController = new OrderController(parent, DB);
			
			String verifyLoan = "SELECT * FROM loans WHERE BID = " + BID + " AND BCID = " + BCID
					+ " AND (STATUS = '" + Loan.OPEN_LOAN_VALID + "' OR STATUS + '" + Loan.OPEN_LOAN_DELAYED + "')";
			
			if (!UID.equals("")){	//UID is not mandatory
				if (!memberController.ValidateMember(UID)){
					SendOutputToUser("ERROR","No such member",Message.RETURN_BOOK_RESPONSE,client);
					return 0;
				}else verifyLoan += " AND UID = " + UID;
			}
				
			if (!bookController.ValidateBook(BID)){
				SendOutputToUser("ERROR","No such book",Message.RETURN_BOOK_RESPONSE,client);
				return 0;
			}
			
			if(!bookController.ValidateBookCopy(BID, BCID)){
				SendOutputToUser("ERROR","No such book copy",Message.RETURN_BOOK_RESPONSE,client);
				return 0;
			}
					
	
			ResultSet rs = DB.Query(verifyLoan);
			boolean isValid = false;
			String expectedReturnDate = "";
			int loanStatus = -1;
			int availablecopies = -1;
		
			while(rs.next()){
				switch(rs.getInt("STATUS")){
				case Loan.OPEN_LOAN_DELAYED:{}
				case Loan.OPEN_LOAN_VALID:{
					isValid = true;
					expectedReturnDate = rs.getString("RETURN_DATE");
					loanStatus = rs.getInt("STATUS");
					availablecopies = rs.getInt("AVAILABLECOPIES");
				}
				}
			}

		
			if (!isValid){
				SendOutputToUser("ERROR","No such book loan",Message.RETURN_BOOK_RESPONSE,client);
				return 0;
			}
			
			if (!bookController.isBCIDLoaned(BID, BCID)){
				SendOutputToUser("ERROR","Specific book copy is not loaned",Message.RETURN_BOOK_RESPONSE,client);
				return 0;
			}
			
			if (loanStatus == -1){
				parent.Log("[ReturnBook] Could not verify loan status. [" + client.getInetAddress() + "]. ");
				SendOutputToUser("ERROR","Could not verify loan status",Message.RETURN_BOOK_RESPONSE,client);
				return 0;
			}
			
			if (availablecopies == -1){
				parent.Log("[ReturnBook] Could not get available copies for book. [" + client.getInetAddress() + "]. ");
				SendOutputToUser("ERROR","Could not get available copies for book",Message.RETURN_BOOK_RESPONSE,client);
				return 0;
			}
	
			
					
			int year = Integer.parseInt(expectedReturnDate.substring(0, 4));
			int month = Integer.parseInt(expectedReturnDate.substring(5, 7));
			int day = Integer.parseInt(expectedReturnDate.substring(8, expectedReturnDate.length()));
			Calendar expectedReturn = Calendar.getInstance();
			expectedReturn.set(year, month-1, day);
			expectedReturn.setLenient(false);
			
			Calendar today = Calendar.getInstance();
			long DayInMillis = 1000 * 60 * 60 * 24; 	//millis * sec * min * hour = 1 day
			if (((today.getTimeInMillis() - expectedReturn.getTimeInMillis())/DayInMillis) < 0){
				loanStatus = Loan.CLOSED_LOAN_DELAYED;
			}else loanStatus = Loan.CLOSED_LOAN_VALID;
			
			String actualReturnDate = today.get(Calendar.YEAR) + "-";
			if (today.get(Calendar.MONTH) < 10) actualReturnDate += "0" + (today.get(Calendar.MONTH) + 1) + "-";
			else actualReturnDate += (today.get(Calendar.MONTH) + 1) + "-";
			if (today.get(Calendar.DAY_OF_MONTH) < 10) actualReturnDate += "0" + today.get(Calendar.DAY_OF_MONTH);
			else actualReturnDate += today.get(Calendar.DAY_OF_MONTH);
			
			
			String closeLoan = "UPDATE loans SET ACTUAL_RETURN_DATE = '" + actualReturnDate + "' AND STATUS = '" + loanStatus
					+ "' AND BOOKSTATUS = '" + BOOKSTATUS + "'";
			
			if (DB.Update(closeLoan) == 0){
				SendOutputToUser("ERROR","Could not close loan (sql error)",Message.RETURN_BOOK_RESPONSE,client);
				parent.Log("[ReturnBook] Could not close loan (sql error): " + closeLoan + ". [" + client.getInetAddress() + "]. ");
				return 0;
			}
			
			if (BOOKSTATUS == Loan.LOAN_BOOK_LOST){
				bookController.DeleteBookCopy(BID, BCID, 0);
			}else{
				bookController.setAvailableCopies(BID, ++availablecopies);
			}
			
			int notifytoBID = orderController.getHeadOfOrderList(BID);
			
			String name = bookController.getNameForBook(BID);
			MessageController messageController = new MessageController(parent, DB);
			
			Calendar todayDate = Calendar.getInstance();
			String currDate = todayDate.get(Calendar.YEAR) + "-";
			if (todayDate.get(Calendar.MONTH) < 10) currDate += "0" + (todayDate.get(Calendar.MONTH) + 1) + "-";
			else currDate += (todayDate.get(Calendar.MONTH) + 1) + "-";
			if (todayDate.get(Calendar.DAY_OF_MONTH) < 10) currDate += "0" + todayDate.get(Calendar.DAY_OF_MONTH);
			else currDate += todayDate.get(Calendar.DAY_OF_MONTH);
			
			ArrayList<String> msgData = new ArrayList<String>();
			msgData.add(String.valueOf(UID));
			msgData.add("Your Book has arrived!");
			msgData.add("Your Book," + name + ", has arrived. Please come and take it");
			msgData.add(String.valueOf(SystemMesseges.SYSTEM_MESSAGE));
			msgData.add(currDate);
			msgData.add(String.valueOf(SystemMesseges.MESSAGE_UNREAD));
			messageController.CreateMessage(data, client);
			
			
		}catch(SQLException e){
			parent.Log("[ReturnBook] SQLException. [" + client.getInetAddress() + "]. " + e.getMessage());
			return 0;
		}catch(IndexOutOfBoundsException in){
			parent.Log("[ReturnBook] IndexOutOfBoundsException. [" + client.getInetAddress() + "]. " + in.getMessage());
			return 0;
		}catch(ClassCastException cl){
			parent.Log("[ReturnBook] ClassCastException. [" + client.getInetAddress() + "]. " + cl.getMessage());
			return 0;
		}
		return 1;
	}
	
	
	
	/**
	 * This message will handle message output to the user
	 * (When only needs to send a text message without extra data)
	 * @param status - String - "OK" or "ERROR"
	 * @param message - String - containing the message
	 * @param action - int - the message type
	 * @param client - the client to send to
	 */
	private void SendOutputToUser(String status,String message,int action,ConnectionToClient client){
		
		ArrayList<String> indexOUT = new ArrayList<String>();
		ArrayList<Object> dataOUT = new ArrayList<Object>();
		
		indexOUT.add(status);
		dataOUT.add(message);
		Message toSend = new Message(indexOUT,dataOUT,action);
		try{
			client.sendToClient(toSend);	
		}catch(IOException e){
			parent.Log("[SendOutputToUser] IOException - send message. [" + client.getInetAddress() + "]. ");
		}

	}
}
